import time
import redis
from fastapi import Request
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
import structlog
from datetime import datetime

from config.settings import settings

logger = structlog.get_logger()


class RateLimitMiddleware(BaseHTTPMiddleware):
    def __init__(self, app):
        super().__init__(app)
        self.redis_client = None
        self.rate_limit = settings.rate_limit
        self.window = settings.rate_limit_window
        self._redis_connection_failed = False

    async def dispatch(self, request: Request, call_next):
        # 🔥 限流中间件调试输出
        logger.info("=" * 50)
        logger.info(f"⏱️ 限流中间件: 检查请求频率 ,时间: {datetime.now().strftime('%H:%M:%S.%f')[:-3]} ,路径: {request.url.path} ,限流配置: {self.rate_limit}次/{self.window}秒")

        # 初始化Redis连接
        if self.redis_client is None and not self._redis_connection_failed:
            try:
                self.redis_client = redis.from_url(
                    settings.redis_url,
                    decode_responses=True,
                    socket_connect_timeout=5,
                    socket_timeout=5,
                    retry_on_timeout=True
                )
                self.redis_client.ping()
                self._redis_connection_failed = False
                logger.info("   ✅ Redis连接成功")
            except Exception as e:
                logger.info(f"   ❌ Redis连接失败: {str(e)}")
                logger.info("⏱️" + "=" * 50)
                logger.error("Failed to connect to Redis", error=str(e))
                self._redis_connection_failed = True
                response = await call_next(request)
                return response

        # 如果之前连接失败，直接跳过限流
        if self._redis_connection_failed:
            print("   ⚠️ Redis不可用，跳过限流")
            print("⏱️" + "=" * 50)
            response = await call_next(request)
            return response

        # 获取客户端IP
        client_ip = request.headers.get("X-Forwarded-For", request.client.host)
        if "," in client_ip:
            client_ip = client_ip.split(",")[0].strip()

        logger.info(f"   客户端IP: {client_ip}")

        # 创建限流key
        key = f"rate_limit:{client_ip}"
        logger.info(f"   限流Key: {key}")

        try:
            # 使用Redis实现滑动窗口限流
            current_time = int(time.time())
            pipeline = self.redis_client.pipeline()

            # 移除过期的请求记录
            pipeline.zremrangebyscore(key, 0, current_time - self.window)
            # 获取当前窗口内的请求数
            pipeline.zcard(key)
            # 添加当前请求
            pipeline.zadd(key, {str(current_time): current_time})
            # 设置key的过期时间
            pipeline.expire(key, self.window)

            results = pipeline.execute()
            current_requests = results[1]

            # print(f"   当前窗口请求数: {current_requests}")
            # print(f"   限流阈值: {self.rate_limit}")

            # 检查是否超过限流
            if current_requests >= self.rate_limit:
                # 移除当前请求记录
                self.redis_client.zrem(key, str(current_time))

                # print("   🚫 触发限流！")
                # print("⏱️" + "=" * 50)

                logger.warning(
                    "Rate limit exceeded",
                    client_ip=client_ip,
                    current_requests=current_requests,
                    limit=self.rate_limit
                )

                return Response(
                    content='{"detail": "Rate limit exceeded"}',
                    status_code=429,
                    headers={
                        "Retry-After": str(self.window),
                        "X-RateLimit-Limit": str(self.rate_limit),
                        "X-RateLimit-Remaining": "0",
                        "X-RateLimit-Reset": str(current_time + self.window)
                    },
                    media_type="application/json"
                )

            # 获取剩余请求数
            remaining = self.rate_limit - current_requests - 1
            # print(f"   ✅ 限流检查通过")
            # print(f"   剩余请求数: {remaining}")
            # print("⏱️" + "=" * 50)

            response = await call_next(request)

            # 添加响应头
            response.headers["X-RateLimit-Limit"] = str(self.rate_limit)
            response.headers["X-RateLimit-Remaining"] = str(remaining)
            response.headers["X-RateLimit-Reset"] = str(current_time + self.window)

            return response

        except Exception as e:
            # print(f"   ❌ 限流检查出错: {str(e)}")
            # print("   ⚠️ 允许请求通过")
            # print("⏱️" + "=" * 50)
            logger.error("Rate limiting error", error=str(e))
            response = await call_next(request)
            return response